PageRenderTime 54ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/projects/netbeans-7.3/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/csm/NamespaceImpl.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 810 lines | 610 code | 82 blank | 118 comment | 132 complexity | 367fff1462d7dead13e4a58bf15e0cb6 MD5 | raw file
  1. /*
  2. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  3. *
  4. * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
  5. *
  6. * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  7. * Other names may be trademarks of their respective owners.
  8. *
  9. * The contents of this file are subject to the terms of either the GNU
  10. * General Public License Version 2 only ("GPL") or the Common
  11. * Development and Distribution License("CDDL") (collectively, the
  12. * "License"). You may not use this file except in compliance with the
  13. * License. You can obtain a copy of the License at
  14. * http://www.netbeans.org/cddl-gplv2.html
  15. * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  16. * specific language governing permissions and limitations under the
  17. * License. When distributing the software, include this License Header
  18. * Notice in each file and include the License file at
  19. * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
  20. * particular file as subject to the "Classpath" exception as provided
  21. * by Oracle in the GPL Version 2 section of the License file that
  22. * accompanied this code. If applicable, add the following below the
  23. * License Header, with the fields enclosed by brackets [] replaced by
  24. * your own identifying information:
  25. * "Portions Copyrighted [year] [name of copyright owner]"
  26. *
  27. * Contributor(s):
  28. *
  29. * The Original Software is NetBeans. The Initial Developer of the Original
  30. * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
  31. * Microsystems, Inc. All Rights Reserved.
  32. *
  33. * If you wish your version of this file to be governed by only the CDDL
  34. * or only the GPL Version 2, indicate your decision by adding
  35. * "[Contributor] elects to include this software in this distribution
  36. * under the [CDDL or GPL Version 2] license." If you do not indicate a
  37. * single choice of license, a recipient has the option to distribute
  38. * your version of this file under either the CDDL, the GPL Version 2 or
  39. * to extend the choice of license to its licensees as provided above.
  40. * However, if you add GPL Version 2 code and therefore, elected the GPL
  41. * Version 2 license, then the option applies only if the new code is
  42. * made subject to such option by the copyright holder.
  43. */
  44. package org.netbeans.modules.cnd.modelimpl.csm;
  45. import org.netbeans.modules.cnd.modelimpl.content.project.ProjectComponent;
  46. import org.netbeans.modules.cnd.modelimpl.content.project.DeclarationContainerNamespace;
  47. import org.netbeans.modules.cnd.modelimpl.content.project.DeclarationContainer;
  48. import java.io.IOException;
  49. import java.lang.ref.Reference;
  50. import java.lang.ref.WeakReference;
  51. import java.util.concurrent.ConcurrentHashMap;
  52. import java.util.concurrent.locks.ReadWriteLock;
  53. import java.util.concurrent.locks.ReentrantReadWriteLock;
  54. import org.netbeans.modules.cnd.api.model.*;
  55. import java.util.*;
  56. import org.netbeans.modules.cnd.api.model.CsmDeclaration.Kind;
  57. import org.netbeans.modules.cnd.api.model.services.CsmSelect.CsmFilter;
  58. import org.netbeans.modules.cnd.api.model.util.CsmKindUtilities;
  59. import org.netbeans.modules.cnd.api.model.util.UIDs;
  60. import org.netbeans.modules.cnd.modelimpl.csm.core.*;
  61. import org.netbeans.modules.cnd.modelimpl.debug.DiagnosticExceptoins;
  62. import org.netbeans.modules.cnd.modelimpl.debug.TraceFlags;
  63. import org.netbeans.modules.cnd.modelimpl.repository.PersistentUtils;
  64. import org.netbeans.modules.cnd.modelimpl.repository.RepositoryUtils;
  65. import org.netbeans.modules.cnd.modelimpl.textcache.QualifiedNameCache;
  66. import org.netbeans.modules.cnd.modelimpl.uid.UIDCsmConverter;
  67. import org.netbeans.modules.cnd.modelimpl.uid.UIDObjectFactory;
  68. import org.netbeans.modules.cnd.modelimpl.uid.UIDUtilities;
  69. import org.netbeans.modules.cnd.repository.spi.Persistent;
  70. import org.netbeans.modules.cnd.repository.support.SelfPersistent;
  71. import org.openide.util.CharSequences;
  72. import org.netbeans.modules.cnd.modelimpl.textcache.NameCache;
  73. import org.netbeans.modules.cnd.repository.spi.Key;
  74. import org.netbeans.modules.cnd.repository.spi.RepositoryDataInput;
  75. import org.netbeans.modules.cnd.repository.spi.RepositoryDataOutput;
  76. /**
  77. * CsmNamespace implementation
  78. * @author Vladimir Kvashin
  79. */
  80. public class NamespaceImpl implements CsmNamespace, MutableDeclarationsContainer,
  81. Persistent, SelfPersistent, Disposable, CsmIdentifiable {
  82. private static final CharSequence GLOBAL = CharSequences.create("$Global$"); // NOI18N
  83. // only one of project/projectUID must be used (based on USE_UID_TO_CONTAINER)
  84. private Object projectRef;// can be set in onDispose or contstructor only
  85. private final CsmUID<CsmProject> projectUID;
  86. // only one of parent/parentUID must be used (based on USE_UID_TO_CONTAINER)
  87. private /*final*/ CsmNamespace parentRef;// can be set in onDispose or contstructor only
  88. private final CsmUID<CsmNamespace> parentUID;
  89. private final CharSequence name;
  90. private final CharSequence qualifiedName;
  91. /** maps namespaces FQN to namespaces */
  92. private final Map<CharSequence, CsmUID<CsmNamespace>> nestedNamespaces;
  93. private final Key declarationsSorageKey;
  94. private final Set<CsmUID<CsmOffsetableDeclaration>> unnamedDeclarations;
  95. private final TreeMap<FileNameSortedKey, CsmUID<CsmNamespaceDefinition>> nsDefinitions;
  96. private final ReadWriteLock nsDefinitionsLock = new ReentrantReadWriteLock();
  97. private final ReentrantReadWriteLock projectLock = new ReentrantReadWriteLock();
  98. private final boolean global;
  99. /** Constructor used for global namespace */
  100. private NamespaceImpl(ProjectBase project, boolean fake) {
  101. this.name = GLOBAL;
  102. this.qualifiedName = CharSequences.empty(); // NOI18N
  103. this.parentUID = null;
  104. this.parentRef = null;
  105. this.global = true;
  106. assert project != null;
  107. this.projectUID = UIDCsmConverter.projectToUID(project);
  108. assert this.projectUID != null;
  109. unnamedDeclarations = Collections.synchronizedSet(new HashSet<CsmUID<CsmOffsetableDeclaration>>());
  110. nestedNamespaces = new ConcurrentHashMap<CharSequence, CsmUID<CsmNamespace>>();
  111. nsDefinitions = new TreeMap<FileNameSortedKey, CsmUID<CsmNamespaceDefinition>>(defenitionComparator);
  112. this.projectRef = new WeakReference<ProjectBase>(project);
  113. this.declarationsSorageKey = fake ? null : new DeclarationContainerNamespace(this).getKey();
  114. }
  115. public static NamespaceImpl create(ProjectBase project, boolean fake) {
  116. NamespaceImpl namespaceImpl = new NamespaceImpl(project, fake);
  117. if (!fake) {
  118. project.registerNamespace(namespaceImpl);
  119. }
  120. return namespaceImpl;
  121. }
  122. private static final boolean CHECK_PARENT = false;
  123. protected NamespaceImpl(ProjectBase project, NamespaceImpl parent, String name, String qualifiedName) {
  124. this.name = NameCache.getManager().getString(name);
  125. this.global = false;
  126. assert project != null;
  127. this.projectUID = UIDCsmConverter.projectToUID(project);
  128. assert this.projectUID != null;
  129. unnamedDeclarations = Collections.synchronizedSet(new HashSet<CsmUID<CsmOffsetableDeclaration>>());
  130. nestedNamespaces = new ConcurrentHashMap<CharSequence, CsmUID<CsmNamespace>>();
  131. nsDefinitions = new TreeMap<FileNameSortedKey,CsmUID<CsmNamespaceDefinition>>(defenitionComparator);
  132. this.projectRef = new WeakReference<ProjectBase>(project);
  133. this.qualifiedName = QualifiedNameCache.getManager().getString(qualifiedName);
  134. // TODO: rethink once more
  135. // now all classes do have namespaces
  136. // // TODO: this makes parent-child relationships assymetric, that's bad;
  137. // // on the other hand I dont like an idea of top-level namespaces' getParent() returning non-null
  138. // // Probably the CsmProject should have 2 methods:
  139. // // getGlobalNamespace() and getTopLevelNamespaces()
  140. // this.parent = (parent == null || parent.isGlobal()) ? null : parent;
  141. assert !CHECK_PARENT || parent != null;
  142. this.parentUID = UIDCsmConverter.namespaceToUID(parent);
  143. assert parentUID != null || parent == null;
  144. this.parentRef = null;
  145. declarationsSorageKey = new DeclarationContainerNamespace(this).getKey();
  146. }
  147. public static NamespaceImpl create(ProjectBase project, NamespaceImpl parent, String name, String qualifiedName) {
  148. NamespaceImpl namespaceImpl = new NamespaceImpl(project, parent, name, qualifiedName);
  149. project.registerNamespace(namespaceImpl);
  150. if( parent != null ) {
  151. // nb: this.parent should be set first, since getQualidfiedName request parent's fqn
  152. parent.addNestedNamespace(namespaceImpl);
  153. }
  154. namespaceImpl.notify(namespaceImpl, NotifyEvent.NAMESPACE_ADDED);
  155. return namespaceImpl;
  156. }
  157. protected enum NotifyEvent {
  158. DECLARATION_ADDED,
  159. DECLARATION_REMOVED,
  160. NAMESPACE_ADDED,
  161. NAMESPACE_REMOVED,
  162. }
  163. protected void notify(CsmObject obj, NotifyEvent kind) {
  164. switch (kind) {
  165. case DECLARATION_ADDED:
  166. assert obj instanceof CsmOffsetableDeclaration;
  167. if (!ForwardClass.isForwardClass((CsmOffsetableDeclaration)obj)) {
  168. // no need to notify about fake classes
  169. Notificator.instance().registerNewDeclaration((CsmOffsetableDeclaration)obj);
  170. }
  171. break;
  172. case DECLARATION_REMOVED:
  173. assert obj instanceof CsmOffsetableDeclaration;
  174. if (!ForwardClass.isForwardClass((CsmOffsetableDeclaration)obj)) {
  175. // no need to notify about fake classes
  176. Notificator.instance().registerRemovedDeclaration((CsmOffsetableDeclaration)obj);
  177. }
  178. break;
  179. case NAMESPACE_ADDED:
  180. assert obj instanceof CsmNamespace;
  181. assert !((CsmNamespace)obj).isGlobal();
  182. Notificator.instance().registerNewNamespace((CsmNamespace)obj);
  183. break;
  184. case NAMESPACE_REMOVED:
  185. assert obj instanceof CsmNamespace;
  186. assert !((CsmNamespace)obj).isGlobal();
  187. Notificator.instance().registerRemovedNamespace((CsmNamespace)obj);
  188. break;
  189. default:
  190. throw new IllegalArgumentException("unexpected kind " + kind); // NOI18N
  191. }
  192. }
  193. @Override
  194. public void dispose() {
  195. onDispose();
  196. notify(this, NotifyEvent.NAMESPACE_REMOVED);
  197. }
  198. private void onDispose() {
  199. projectLock.writeLock().lock();
  200. try {
  201. if (projectRef == null) {
  202. // restore container from it's UID
  203. this.projectRef = (ProjectBase) UIDCsmConverter.UIDtoProject(this.projectUID);
  204. assert this.projectRef != null || this.projectUID == null : "no object for UID " + this.projectUID;
  205. }
  206. if (parentRef == null) {
  207. // restore container from it's UID
  208. this.parentRef = UIDCsmConverter.UIDtoNamespace(this.parentUID);
  209. assert this.parentRef != null || this.parentUID == null : "no object for UID " + this.parentUID;
  210. }
  211. } finally {
  212. projectLock.writeLock().unlock();
  213. }
  214. weakDeclarationContainer = null;
  215. }
  216. private static final String UNNAMED_PREFIX = "<unnamed>"; // NOI18N
  217. private Set<Integer> unnamedNrs = new HashSet<Integer>();
  218. public String getNameForUnnamedElement() {
  219. String out = UNNAMED_PREFIX;
  220. int minVal = getMinUnnamedValue();
  221. if (minVal != 0) {
  222. out = out + minVal;
  223. }
  224. unnamedNrs.add(Integer.valueOf(minVal));
  225. return out;
  226. }
  227. private int getMinUnnamedValue() {
  228. for (int i = 0; i < unnamedNrs.size(); i++) {
  229. if (!unnamedNrs.contains(Integer.valueOf(i))) {
  230. return i;
  231. }
  232. }
  233. return unnamedNrs.size();
  234. }
  235. @Override
  236. public CsmNamespace getParent() {
  237. return _getParentNamespace();
  238. }
  239. @Override
  240. public Collection<CsmNamespace> getNestedNamespaces() {
  241. Collection<CsmNamespace> out = UIDCsmConverter.UIDsToNamespaces(new ArrayList<CsmUID<CsmNamespace>>(nestedNamespaces.values()));
  242. return out;
  243. }
  244. private WeakReference<DeclarationContainerNamespace> weakDeclarationContainer = TraceFlags.USE_WEAK_MEMORY_CACHE ? new WeakReference<DeclarationContainerNamespace>(null) : null;
  245. private int preventMultiplyDiagnosticExceptions = 0;
  246. private DeclarationContainerNamespace getDeclarationsSorage() {
  247. if (declarationsSorageKey == null) {
  248. return DeclarationContainerNamespace.empty();
  249. }
  250. DeclarationContainerNamespace dc = null;
  251. WeakReference<DeclarationContainerNamespace> weak = null;
  252. if (TraceFlags.USE_WEAK_MEMORY_CACHE) {
  253. weak = weakDeclarationContainer;
  254. if (weak != null) {
  255. dc = weak.get();
  256. if (dc != null) {
  257. return dc;
  258. }
  259. }
  260. }
  261. dc = (DeclarationContainerNamespace) RepositoryUtils.get(declarationsSorageKey);
  262. if (dc == null && preventMultiplyDiagnosticExceptions < DiagnosticExceptoins.LimitMultiplyDiagnosticExceptions) {
  263. DiagnosticExceptoins.registerIllegalRepositoryStateException("Failed to get DeclarationsSorage by key ", declarationsSorageKey); // NOI18N
  264. preventMultiplyDiagnosticExceptions++;
  265. }
  266. if (TraceFlags.USE_WEAK_MEMORY_CACHE && dc != null && weakDeclarationContainer != null) {
  267. weakDeclarationContainer = new WeakReference<DeclarationContainerNamespace>(dc);
  268. }
  269. return dc != null ? dc : DeclarationContainerNamespace.empty();
  270. }
  271. @Override
  272. public Collection<CsmOffsetableDeclaration> getDeclarations() {
  273. DeclarationContainer declStorage = getDeclarationsSorage();
  274. // add all declarations
  275. Collection<CsmUID<CsmOffsetableDeclaration>> uids = declStorage.getDeclarationsUIDs();
  276. // add all unnamed declarations
  277. synchronized (unnamedDeclarations) {
  278. uids.addAll(unnamedDeclarations);
  279. }
  280. // convert to objects
  281. Collection<CsmOffsetableDeclaration> decls = UIDCsmConverter.UIDsToDeclarations(uids);
  282. return decls;
  283. }
  284. public Iterator<CsmOffsetableDeclaration> getDeclarations(CsmFilter filter) {
  285. DeclarationContainer declStorage = getDeclarationsSorage();
  286. // add all declarations
  287. Collection<CsmUID<CsmOffsetableDeclaration>> uids = declStorage.getDeclarationsUIDs();
  288. // add all unnamed declarations
  289. synchronized (unnamedDeclarations) {
  290. uids.addAll(unnamedDeclarations);
  291. }
  292. return UIDCsmConverter.UIDsToDeclarations(uids, filter);
  293. }
  294. public Collection<CsmUID<CsmOffsetableDeclaration>> findUidsByPrefix(String prefix) {
  295. // To improve performance use char(255) instead real Character.MAX_VALUE
  296. char maxChar = 255; //Character.MAX_VALUE;
  297. return findUidsRange(prefix, prefix+maxChar);
  298. }
  299. public Collection<CsmUID<CsmOffsetableDeclaration>> findUidsRange(String from, String to) {
  300. DeclarationContainer declStorage = getDeclarationsSorage();
  301. return declStorage.getUIDsRange(from, to);
  302. }
  303. public Collection<CsmOffsetableDeclaration> getDeclarationsRange(CharSequence fqn, Kind[] kinds) {
  304. DeclarationContainer declStorage = getDeclarationsSorage();
  305. return declStorage.getDeclarationsRange(fqn, kinds);
  306. }
  307. public Collection<CsmUID<CsmOffsetableDeclaration>> getUnnamedUids() {
  308. // add all declarations
  309. Collection<CsmUID<CsmOffsetableDeclaration>> uids;
  310. // add all unnamed declarations
  311. synchronized (unnamedDeclarations) {
  312. uids = new ArrayList<CsmUID<CsmOffsetableDeclaration>>(unnamedDeclarations);
  313. }
  314. return uids;
  315. }
  316. @Override
  317. public boolean isGlobal() {
  318. return global;
  319. }
  320. @Override
  321. public CharSequence getQualifiedName() {
  322. return qualifiedName;
  323. }
  324. @Override
  325. public CharSequence getName() {
  326. return name;
  327. }
  328. private void addNestedNamespace(NamespaceImpl nsp) {
  329. assert nsp != null;
  330. CsmUID<CsmNamespace> nestedNsUid = RepositoryUtils.put((CsmNamespace)nsp);
  331. assert nestedNsUid != null;
  332. nestedNamespaces.put(nsp.getQualifiedName(), nestedNsUid);
  333. RepositoryUtils.put(this);
  334. }
  335. private void removeNestedNamespace(NamespaceImpl nsp) {
  336. assert nsp != null;
  337. CsmUID<CsmNamespace> nestedNsUid = nestedNamespaces.remove(nsp.getQualifiedName());
  338. assert nestedNsUid != null;
  339. // handle unnamed namespace index
  340. if (nsp.getName().length() == 0) {
  341. String fqn = nsp.getQualifiedName().toString();
  342. int greaterInd = fqn.lastIndexOf('>');
  343. assert greaterInd >= 0;
  344. if (greaterInd + 1 < fqn.length()) {
  345. try {
  346. Integer index = Integer.parseInt(fqn.substring(greaterInd+1));
  347. unnamedNrs.remove(index);
  348. } catch (NumberFormatException ex) {
  349. DiagnosticExceptoins.register(ex);
  350. }
  351. } else {
  352. unnamedNrs.remove(Integer.valueOf(0));
  353. }
  354. }
  355. RepositoryUtils.put(this);
  356. }
  357. /**
  358. * Determines whether a variable has namespace or global scope
  359. *
  360. * @param v variable to check.
  361. * NB: should be file- or namespace- level,
  362. * don't pass a field, a parameter or a local var!
  363. *
  364. * @param isFileLevel true if it's defined on file level,
  365. * otherwise (if it's defined in namespace definition) false
  366. *
  367. * @return true if the variable has namesapce scope or global scope,
  368. * or false if it is file-local scope (i.e. no external linkage)
  369. */
  370. public static boolean isNamespaceScope(VariableImpl<?> var, boolean isFileLevel) {
  371. if( ((FileImpl) var.getContainingFile()).isHeaderFile() && ! CsmKindUtilities.isVariableDefinition(var)) {
  372. return true;
  373. } else if( var.isStatic() ) {
  374. return false;
  375. }
  376. else if( var.isConst() && isFileLevel ) {
  377. if( ! var.isExtern() ) {
  378. return false;
  379. }
  380. }
  381. return true;
  382. }
  383. /**
  384. * Determines whether a function has namesace scope
  385. *
  386. * @param func function to check.
  387. *
  388. * @return true if the function has namesapce scope or global scope,
  389. * or false if it is file-local scope (i.e. no external linkage)
  390. */
  391. public static boolean isNamespaceScope(FunctionImpl<?> func) {
  392. if( ((FileImpl) func.getContainingFile()).isHeaderFile() && ! func.isPureDefinition() ) {
  393. return true;
  394. } else if (func.isStatic()) {
  395. return false;
  396. }
  397. return true;
  398. }
  399. /**
  400. * Determines whether a function has namesace scope
  401. *
  402. * @param func function to check.
  403. *
  404. * @return true if the function has namesapce scope or global scope,
  405. * or false if it is file-local scope (i.e. no external linkage)
  406. */
  407. public static boolean isNamespaceScope(CsmFile file, boolean pureDefinition, boolean _static) {
  408. if( ((FileImpl) file).isHeaderFile() && ! pureDefinition ) {
  409. return true;
  410. } else if (_static) {
  411. return false;
  412. }
  413. return true;
  414. }
  415. @Override
  416. public CsmOffsetableDeclaration findExistingDeclaration(int start, int end, CharSequence name) {
  417. throw new UnsupportedOperationException();
  418. }
  419. @Override
  420. public CsmOffsetableDeclaration findExistingDeclaration(int start, CharSequence name, CsmDeclaration.Kind kind) {
  421. throw new UnsupportedOperationException();
  422. }
  423. @Override
  424. public void addDeclaration(CsmOffsetableDeclaration declaration) {
  425. boolean unnamed = !Utils.canRegisterDeclaration(declaration);
  426. // allow to register any enum
  427. if(unnamed && !CsmKindUtilities.isEnum(declaration) ) {
  428. return;
  429. }
  430. // TODO: remove this dirty hack!
  431. if( (declaration instanceof VariableImpl<?>) ) {
  432. VariableImpl<?> v = (VariableImpl<?>) declaration;
  433. if( isNamespaceScope(v, isGlobal()) ) {
  434. v.setScope(this);
  435. } else {
  436. return;
  437. }
  438. }
  439. if (unnamed) {
  440. unnamedDeclarations.add(UIDCsmConverter.declarationToUID(declaration));
  441. } else {
  442. getDeclarationsSorage().putDeclaration(declaration);
  443. }
  444. // update repository
  445. RepositoryUtils.put(this);
  446. notify(declaration, NotifyEvent.DECLARATION_ADDED);
  447. }
  448. @SuppressWarnings("unchecked")
  449. @Override
  450. public void removeDeclaration(CsmOffsetableDeclaration declaration) {
  451. CsmUID<CsmOffsetableDeclaration> declarationUid;
  452. if (declaration.getName().length() == 0) {
  453. declarationUid = UIDs.get(declaration);
  454. unnamedDeclarations.remove(declarationUid);
  455. } else {
  456. getDeclarationsSorage().removeDeclaration(declaration);
  457. }
  458. // do not clean repository, it must be done from physical container of declaration
  459. if (false) { RepositoryUtils.remove(declarationUid, declaration); }
  460. // update repository
  461. RepositoryUtils.put(this);
  462. notify(declaration, NotifyEvent.DECLARATION_REMOVED);
  463. }
  464. @Override
  465. public Collection<CsmNamespaceDefinition> getDefinitions() {
  466. List<CsmUID<CsmNamespaceDefinition>> uids = new ArrayList<CsmUID<CsmNamespaceDefinition>>();
  467. try {
  468. nsDefinitionsLock.readLock().lock();
  469. uids.addAll(nsDefinitions.values());
  470. } finally {
  471. nsDefinitionsLock.readLock().unlock();
  472. }
  473. Collection<CsmNamespaceDefinition> defs = UIDCsmConverter.UIDsToDeclarations(uids);
  474. return defs;
  475. }
  476. public void addNamespaceDefinition(CsmNamespaceDefinition def) {
  477. CsmUID<CsmNamespaceDefinition> definitionUid = RepositoryUtils.put(def);
  478. boolean add = false;
  479. try {
  480. nsDefinitionsLock.writeLock().lock();
  481. add = nsDefinitions.isEmpty();
  482. nsDefinitions.put(getSortKey(def), definitionUid);
  483. } finally {
  484. nsDefinitionsLock.writeLock().unlock();
  485. }
  486. // update repository
  487. RepositoryUtils.put(this);
  488. if (add){
  489. addRemoveInParentNamespace(true);
  490. }
  491. }
  492. private synchronized void addRemoveInParentNamespace(boolean add){
  493. if (add){
  494. // add this namespace in the parent namespace
  495. NamespaceImpl parent = (NamespaceImpl) _getParentNamespace();
  496. if (parent != null) {
  497. parent.addNestedNamespace(this);
  498. }
  499. _getProject().registerNamespace(this);
  500. } else {
  501. // remove this namespace from the parent namespace
  502. try {
  503. nsDefinitionsLock.readLock().lock();
  504. if (!nsDefinitions.isEmpty()) {
  505. // someone already registered in definitions
  506. // do not unregister
  507. return;
  508. }
  509. } finally {
  510. nsDefinitionsLock.readLock().unlock();
  511. }
  512. NamespaceImpl parent = (NamespaceImpl) _getParentNamespace();
  513. if (parent != null) {
  514. parent.removeNestedNamespace(this);
  515. }
  516. projectRef = _getProject();
  517. ((ProjectBase)projectRef).unregisterNamesace(this);
  518. dispose();
  519. }
  520. }
  521. public void removeNamespaceDefinition(CsmNamespaceDefinition def) {
  522. assert !this.isGlobal();
  523. boolean remove = false;
  524. CsmUID<CsmNamespaceDefinition> definitionUid = null;
  525. try {
  526. nsDefinitionsLock.writeLock().lock();
  527. definitionUid = nsDefinitions.remove(getSortKey(def));
  528. remove = nsDefinitions.isEmpty();
  529. } finally {
  530. nsDefinitionsLock.writeLock().unlock();
  531. }
  532. // does not remove unregistered declaration from repository, it's responsibility of physical container
  533. if (false) { RepositoryUtils.remove(definitionUid, def); }
  534. // update repository about itself
  535. RepositoryUtils.put(this);
  536. if (remove) {
  537. addRemoveInParentNamespace(false);
  538. }
  539. }
  540. @SuppressWarnings("unchecked")
  541. @Override
  542. public Collection<CsmScopeElement> getScopeElements() {
  543. return (List) getDeclarations();
  544. }
  545. @Override
  546. public CsmProject getProject() {
  547. return _getProject();
  548. }
  549. private CsmUID<CsmNamespace> uid = null;
  550. @Override
  551. public final CsmUID<CsmNamespace> getUID() {
  552. CsmUID<CsmNamespace> out = uid;
  553. if (out == null) {
  554. synchronized (this) {
  555. if (uid == null) {
  556. uid = out = createUID();
  557. }
  558. }
  559. }
  560. return uid;
  561. }
  562. protected CsmUID<CsmNamespace> createUID() {
  563. return UIDUtilities.createNamespaceUID(this);
  564. }
  565. private ProjectBase _getProject() {
  566. Object o = projectRef;
  567. if (o instanceof ProjectBase) {
  568. return (ProjectBase) o;
  569. } else if (o instanceof Reference<?>) {
  570. ProjectBase prj = (ProjectBase)((Reference<?>) o).get();
  571. if (prj != null) {
  572. return prj;
  573. }
  574. }
  575. projectLock.readLock().lock();
  576. try {
  577. ProjectBase prj = null;
  578. if (projectRef instanceof ProjectBase) {
  579. prj = (ProjectBase)projectRef;
  580. } else if (projectRef instanceof Reference<?>) {
  581. @SuppressWarnings("unchecked")
  582. Reference<ProjectBase> ref = (Reference<ProjectBase>) projectRef;
  583. prj = ref.get();
  584. }
  585. if (prj == null) {
  586. prj = (ProjectBase) UIDCsmConverter.UIDtoProject(this.projectUID);
  587. assert (prj != null || this.projectUID == null) : "empty project for UID " + this.projectUID;
  588. projectRef = new WeakReference<ProjectBase>(prj);
  589. }
  590. return prj;
  591. } finally {
  592. projectLock.readLock().unlock();
  593. }
  594. }
  595. private CsmNamespace _getParentNamespace() {
  596. projectLock.readLock().lock();
  597. try {
  598. CsmNamespace ns = this.parentRef;
  599. if (ns == null) {
  600. ns = UIDCsmConverter.UIDtoNamespace(this.parentUID);
  601. assert (ns != null || this.parentUID == null) : "null object for UID " + this.parentUID;
  602. }
  603. return ns;
  604. } finally {
  605. projectLock.readLock().unlock();
  606. }
  607. }
  608. @Override
  609. public String toString() {
  610. StringBuilder sb = new StringBuilder(getName());
  611. sb.append(' ');
  612. sb.append(getQualifiedName());
  613. sb.append(" NamespaceImpl @"); // NOI18N
  614. sb.append(hashCode());
  615. return sb.toString();
  616. }
  617. ////////////////////////////////////////////////////////////////////////////
  618. // impl of persistent
  619. @Override
  620. public void write(RepositoryDataOutput output) throws IOException {
  621. output.writeBoolean(this.global);
  622. UIDObjectFactory theFactory = UIDObjectFactory.getDefaultFactory();
  623. // not null UID
  624. assert this.projectUID != null;
  625. theFactory.writeUID(this.projectUID, output);
  626. // can be null for global ns
  627. assert !CHECK_PARENT || this.parentUID != null || isGlobal();
  628. theFactory.writeUID(this.parentUID, output);
  629. assert this.name != null;
  630. PersistentUtils.writeUTF(name, output);
  631. assert this.qualifiedName != null;
  632. PersistentUtils.writeUTF(qualifiedName, output);
  633. theFactory.writeStringToUIDMap(this.nestedNamespaces, output, false);
  634. ProjectComponent.writeKey(this.declarationsSorageKey, output);
  635. try {
  636. nsDefinitionsLock.readLock().lock();
  637. theFactory.writeNameSortedToUIDMap2(this.nsDefinitions, output, false);
  638. } finally {
  639. nsDefinitionsLock.readLock().unlock();
  640. }
  641. theFactory.writeUIDCollection(this.unnamedDeclarations, output, true);
  642. }
  643. public NamespaceImpl(RepositoryDataInput input) throws IOException {
  644. this.global = input.readBoolean();
  645. UIDObjectFactory theFactory = UIDObjectFactory.getDefaultFactory();
  646. this.projectUID = theFactory.readUID(input);
  647. this.parentUID = theFactory.readUID(input);
  648. // not null UID
  649. assert this.projectUID != null;
  650. assert !CHECK_PARENT || this.parentUID != null || this.global;
  651. this.projectRef = null;
  652. this.parentRef = null;
  653. this.name = PersistentUtils.readUTF(input, NameCache.getManager());
  654. assert this.name != null;
  655. this.qualifiedName = PersistentUtils.readUTF(input, QualifiedNameCache.getManager());
  656. assert this.qualifiedName != null;
  657. int collSize = input.readInt();
  658. if (collSize <= 0) {
  659. nestedNamespaces = new ConcurrentHashMap<CharSequence, CsmUID<CsmNamespace>>(0);
  660. } else {
  661. nestedNamespaces = new ConcurrentHashMap<CharSequence, CsmUID<CsmNamespace>>(collSize);
  662. }
  663. theFactory.readStringToUIDMap(this.nestedNamespaces, input, QualifiedNameCache.getManager(), collSize);
  664. declarationsSorageKey = ProjectComponent.readKey(input);
  665. assert declarationsSorageKey != null : "declarationsSorageKey can not be null";
  666. this.nsDefinitions = theFactory.readNameSortedToUIDMap2(input, null);
  667. collSize = input.readInt();
  668. if (collSize < 0) {
  669. unnamedDeclarations = Collections.synchronizedSet(new HashSet<CsmUID<CsmOffsetableDeclaration>>(0));
  670. } else {
  671. unnamedDeclarations = Collections.synchronizedSet(new HashSet<CsmUID<CsmOffsetableDeclaration>>(collSize));
  672. }
  673. theFactory.readUIDCollection(this.unnamedDeclarations, input, collSize);
  674. }
  675. private static FileNameSortedKey getSortKey(CsmNamespaceDefinition def) {
  676. return new FileNameSortedKey(def);
  677. }
  678. public static final Comparator<FileNameSortedKey> defenitionComparator = new Comparator<FileNameSortedKey>() {
  679. @Override
  680. public int compare(FileNameSortedKey o1, FileNameSortedKey o2) {
  681. return o1.compareTo(o2);
  682. }
  683. };
  684. public static class FileNameSortedKey implements Comparable<FileNameSortedKey>, Persistent, SelfPersistent {
  685. private final int start;
  686. private final int fileIndex;
  687. private FileNameSortedKey(CsmNamespaceDefinition def) {
  688. this(UIDUtilities.getFileID(((FileImpl)def.getContainingFile()).getUID()), def.getStartOffset());
  689. }
  690. private FileNameSortedKey(int fileIndex, int start) {
  691. this.start = start;
  692. this.fileIndex = fileIndex;
  693. }
  694. @Override
  695. public int compareTo(FileNameSortedKey o) {
  696. int res = fileIndex - o.fileIndex;
  697. if (res == 0) {
  698. res = start - o.start;
  699. }
  700. return res;
  701. }
  702. @Override public boolean equals(Object obj) {
  703. if (obj instanceof FileNameSortedKey) {
  704. FileNameSortedKey key = (FileNameSortedKey) obj;
  705. return compareTo(key)==0;
  706. }
  707. return false;
  708. }
  709. @Override public int hashCode() {
  710. int hash = 7;
  711. hash = 37 * hash + this.start;
  712. hash = 37 * hash + this.fileIndex;
  713. return hash;
  714. }
  715. @Override public String toString() {
  716. return "FileNameSortedKey: " + this.fileIndex + "[" + this.start; // NOI18N
  717. }
  718. @Override
  719. public void write(RepositoryDataOutput output) throws IOException {
  720. output.writeInt(start);
  721. output.writeInt(fileIndex);
  722. }
  723. public FileNameSortedKey(RepositoryDataInput input) throws IOException {
  724. start = input.readInt();
  725. fileIndex = input.readInt();
  726. }
  727. }
  728. }