001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.cnd.modelimpl.csm;
043:
044: import antlr.collections.AST;
045: import java.io.DataInput;
046: import java.io.DataOutput;
047: import java.io.IOException;
048: import java.util.ArrayList;
049: import java.util.Collection;
050: import java.util.Iterator;
051: import java.util.List;
052: import org.netbeans.modules.cnd.api.model.CsmClass;
053: import org.netbeans.modules.cnd.api.model.CsmDeclaration;
054: import org.netbeans.modules.cnd.api.model.CsmFile;
055: import org.netbeans.modules.cnd.api.model.CsmNamespace;
056: import org.netbeans.modules.cnd.api.model.CsmNamespaceDefinition;
057: import org.netbeans.modules.cnd.api.model.CsmObject;
058: import org.netbeans.modules.cnd.api.model.CsmOffsetableDeclaration;
059: import org.netbeans.modules.cnd.api.model.CsmQualifiedNamedElement;
060: import org.netbeans.modules.cnd.api.model.CsmType;
061: import org.netbeans.modules.cnd.api.model.CsmUID;
062: import org.netbeans.modules.cnd.api.model.CsmVariable;
063: import org.netbeans.modules.cnd.api.model.CsmVariableDefinition;
064: import org.netbeans.modules.cnd.modelimpl.csm.core.Resolver;
065: import org.netbeans.modules.cnd.modelimpl.parser.generated.CPPTokenTypes;
066: import org.netbeans.modules.cnd.modelimpl.csm.core.ResolverFactory;
067: import org.netbeans.modules.cnd.modelimpl.csm.core.Unresolved;
068: import org.netbeans.modules.cnd.modelimpl.repository.PersistentUtils;
069: import org.netbeans.modules.cnd.modelimpl.textcache.NameCache;
070: import org.netbeans.modules.cnd.modelimpl.textcache.QualifiedNameCache;
071: import org.netbeans.modules.cnd.modelimpl.uid.UIDCsmConverter;
072: import org.netbeans.modules.cnd.modelimpl.uid.UIDObjectFactory;
073:
074: /**
075: *
076: * @author Alexander Simon
077: */
078: public final class VariableDefinitionImpl extends
079: VariableImpl<CsmVariableDefinition> implements
080: CsmVariableDefinition {
081:
082: private CsmUID<CsmVariable> declarationUID;
083: private CharSequence qualifiedName;
084: private final CharSequence[] classOrNspNames;
085:
086: /** Creates a new instance of VariableDefinitionImpl */
087: public VariableDefinitionImpl(AST ast, CsmFile file, CsmType type,
088: String name) {
089: super (ast, file, type, getLastname(name), false);
090: classOrNspNames = getClassOrNspNames(ast);
091: registerInProject();
092: }
093:
094: private static String getLastname(String name) {
095: int i = name.lastIndexOf("::"); // NOI18N
096: if (i >= 0) {
097: name = name.substring(i + 2);
098: }
099: return name;
100: }
101:
102: @Override
103: public CsmDeclaration.Kind getKind() {
104: return CsmDeclaration.Kind.VARIABLE_DEFINITION;
105: }
106:
107: public CsmVariable getDeclaration() {
108: CsmVariable declaration = _getDeclaration();
109: if (declaration == null) {
110: _setDeclaration(null);
111: declaration = findDeclaration();
112: _setDeclaration(declaration);
113: }
114: return declaration;
115: }
116:
117: private CsmVariable _getDeclaration() {
118: // null object is OK here, because of changed cached reference
119: return UIDCsmConverter.UIDtoDeclaration(this .declarationUID);
120: }
121:
122: private void _setDeclaration(CsmVariable decl) {
123: this .declarationUID = UIDCsmConverter.declarationToUID(decl);
124: assert declarationUID != null || decl == null;
125: }
126:
127: @Override
128: public CharSequence getQualifiedName() {
129: if (qualifiedName == null) {
130: qualifiedName = QualifiedNameCache.getManager().getString(
131: findQualifiedName());
132: }
133: return qualifiedName;
134: }
135:
136: private String findQualifiedName() {
137: CsmVariable declaration = _getDeclaration();
138: if (declaration != null) {
139: return declaration.getQualifiedName().toString();
140: }
141: CsmObject owner = findOwner();
142: if (owner instanceof CsmQualifiedNamedElement) {
143: return ((CsmQualifiedNamedElement) owner)
144: .getQualifiedName()
145: + "::" + getQualifiedNamePostfix(); // NOI18N
146: } else {
147: CharSequence[] cnn = classOrNspNames;
148: CsmNamespaceDefinition nsd = findNamespaceDefinition();
149: StringBuilder sb = new StringBuilder();
150: if (nsd != null) {
151: sb.append(nsd.getQualifiedName());
152: }
153: if (cnn != null) {
154: for (int i = 0; i < cnn.length; i++) {
155: if (sb.length() > 0) {
156: sb.append("::"); // NOI18N
157: }
158: sb.append(cnn[i]);
159: }
160: }
161: if (sb.length() == 0) {
162: sb.append("unknown>"); // NOI18N
163: }
164: sb.append("::"); // NOI18N
165: sb.append(getQualifiedNamePostfix());
166: return sb.toString();
167: }
168: }
169:
170: private CsmNamespaceDefinition findNamespaceDefinition() {
171: return findNamespaceDefinition(getContainingFile()
172: .getDeclarations());
173: }
174:
175: private CsmNamespaceDefinition findNamespaceDefinition(
176: Collection/*<CsmOffsetableDeclaration>*/declarations) {
177: for (Iterator it = declarations.iterator(); it.hasNext();) {
178: CsmOffsetableDeclaration decl = (CsmOffsetableDeclaration) it
179: .next();
180: if (decl.getStartOffset() > this .getStartOffset()) {
181: break;
182: }
183: if (decl.getKind() == CsmDeclaration.Kind.NAMESPACE_DEFINITION) {
184: if (this .getEndOffset() < decl.getEndOffset()) {
185: CsmNamespaceDefinition nsdef = (CsmNamespaceDefinition) decl;
186: CsmNamespaceDefinition inner = findNamespaceDefinition(nsdef
187: .getDeclarations());
188: return (inner == null) ? nsdef : inner;
189: }
190: }
191: }
192: return null;
193: }
194:
195: private CsmVariable findDeclaration() {
196: String uname = CsmDeclaration.Kind.VARIABLE.toString()
197: + UNIQUE_NAME_SEPARATOR + getQualifiedName();
198: CsmDeclaration def = getContainingFile().getProject()
199: .findDeclaration(uname);
200: if (def == null) {
201: CsmObject owner = findOwner();
202: if (owner instanceof CsmClass) {
203: def = findByName(((CsmClass) owner).getMembers(),
204: getName());
205: } else if (owner instanceof CsmNamespace) {
206: def = findByName(((CsmNamespace) owner)
207: .getDeclarations(), getName());
208: }
209: }
210: return (CsmVariable) def;
211: }
212:
213: private CsmVariable findByName(
214: Collection/*CsmDeclaration*/declarations, CharSequence name) {
215: for (Iterator it = declarations.iterator(); it.hasNext();) {
216: CsmDeclaration decl = (CsmDeclaration) it.next();
217: if (decl.getName().equals(name)) {
218: if (decl instanceof CsmVariable) { // paranoja
219: return (CsmVariable) decl;
220: }
221: }
222: }
223: return null;
224: }
225:
226: /** @return either class or namespace */
227: private CsmObject findOwner() {
228: CharSequence[] cnn = classOrNspNames;
229: if (cnn != null) {
230: CsmObject obj = ResolverFactory.createResolver(this )
231: .resolve(cnn,
232: Resolver.CLASSIFIER | Resolver.NAMESPACE);
233: if (obj instanceof CsmClass) {
234: if (!(obj instanceof Unresolved.UnresolvedClass)) {
235: return (CsmClass) obj;
236: }
237: } else if (obj instanceof CsmNamespace) {
238: return (CsmNamespace) obj;
239: }
240: }
241: return null;
242: }
243:
244: private static String[] getClassOrNspNames(AST ast) {
245: AST qid = getQialifiedId(ast);
246: if (qid == null) {
247: return null;
248: }
249: int cnt = qid.getNumberOfChildren();
250: if (cnt >= 1) {
251: List/*<String>*/l = new ArrayList/*<String>*/();
252: for (AST token = qid.getFirstChild(); token != null; token = token
253: .getNextSibling()) {
254: if (token.getType() == CPPTokenTypes.ID) {
255: if (token.getNextSibling() != null) {
256: l.add(token.getText());
257: }
258: }
259: }
260: return (String[]) l.toArray(new String[l.size()]);
261: }
262: return null;
263: }
264:
265: private static AST getQialifiedId(AST ast) {
266: AST varAst = ast;
267: for (AST token = varAst.getFirstChild(); token != null; token = token
268: .getNextSibling()) {
269: switch (token.getType()) {
270: case CPPTokenTypes.CSM_VARIABLE_DECLARATION:
271: case CPPTokenTypes.CSM_ARRAY_DECLARATION:
272: return token = token.getFirstChild();
273: case CPPTokenTypes.CSM_QUALIFIED_ID:
274: case CPPTokenTypes.ID:
275: return token;
276: }
277: }
278: return null;
279: }
280:
281: ////////////////////////////////////////////////////////////////////////////
282: // impl of SelfPersistent
283:
284: @Override
285: public void write(DataOutput output) throws IOException {
286: super .write(output);
287: assert this .qualifiedName != null;
288: output.writeUTF(this .qualifiedName.toString());
289: PersistentUtils.writeStrings(this .classOrNspNames, output);
290:
291: UIDObjectFactory.getDefaultFactory().writeUID(
292: this .declarationUID, output);
293: }
294:
295: public VariableDefinitionImpl(DataInput input) throws IOException {
296: super(input);
297: this.qualifiedName = QualifiedNameCache.getManager().getString(
298: input.readUTF());
299: assert this.qualifiedName != null;
300: this.classOrNspNames = PersistentUtils.readStrings(input,
301: NameCache.getManager());
302:
303: this.declarationUID = UIDObjectFactory.getDefaultFactory()
304: .readUID(input);
305: }
306: }
|