001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.codeassist.impl;
011:
012: import java.util.Map;
013:
014: import org.eclipse.jdt.core.compiler.CharOperation;
015: import org.eclipse.jdt.internal.compiler.*;
016: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
017: import org.eclipse.jdt.internal.compiler.env.*;
018:
019: import org.eclipse.jdt.internal.compiler.ast.*;
020: import org.eclipse.jdt.internal.compiler.lookup.*;
021: import org.eclipse.jdt.internal.compiler.parser.*;
022: import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
023: import org.eclipse.jdt.internal.compiler.impl.*;
024: import org.eclipse.jdt.internal.core.NameLookup;
025: import org.eclipse.jdt.internal.core.SearchableEnvironment;
026:
027: public abstract class Engine implements ITypeRequestor {
028:
029: public LookupEnvironment lookupEnvironment;
030:
031: protected CompilationUnitScope unitScope;
032: public SearchableEnvironment nameEnvironment;
033:
034: public AssistOptions options;
035: public CompilerOptions compilerOptions;
036: public boolean forbiddenReferenceIsError;
037: public boolean discouragedReferenceIsError;
038:
039: public boolean importCachesInitialized = false;
040: public char[][][] importsCache;
041: public ImportBinding[] onDemandImportsCache;
042: public int importCacheCount = 0;
043: public int onDemandImportCacheCount = 0;
044: public char[] currentPackageName = null;
045:
046: public Engine(Map settings) {
047: this .options = new AssistOptions(settings);
048: this .compilerOptions = new CompilerOptions(settings);
049: this .forbiddenReferenceIsError = (this .compilerOptions
050: .getSeverity(CompilerOptions.ForbiddenReference) & ProblemSeverities.Error) != 0;
051: this .discouragedReferenceIsError = (this .compilerOptions
052: .getSeverity(CompilerOptions.DiscouragedReference) & ProblemSeverities.Error) != 0;
053: }
054:
055: /**
056: * Add an additional binary type
057: */
058: public void accept(IBinaryType binaryType,
059: PackageBinding packageBinding,
060: AccessRestriction accessRestriction) {
061: lookupEnvironment.createBinaryTypeFrom(binaryType,
062: packageBinding, accessRestriction);
063: }
064:
065: /**
066: * Add an additional compilation unit.
067: */
068: public void accept(ICompilationUnit sourceUnit,
069: AccessRestriction accessRestriction) {
070: CompilationResult result = new CompilationResult(sourceUnit, 1,
071: 1, this .compilerOptions.maxProblemsPerUnit);
072: CompilationUnitDeclaration parsedUnit = this .getParser()
073: .dietParse(sourceUnit, result);
074:
075: lookupEnvironment.buildTypeBindings(parsedUnit,
076: accessRestriction);
077: lookupEnvironment.completeTypeBindings(parsedUnit, true);
078: }
079:
080: /**
081: * Add additional source types (the first one is the requested type, the rest is formed by the
082: * secondary types defined in the same compilation unit).
083: */
084: public void accept(ISourceType[] sourceTypes,
085: PackageBinding packageBinding,
086: AccessRestriction accessRestriction) {
087: CompilationResult result = new CompilationResult(sourceTypes[0]
088: .getFileName(), 1, 1,
089: this .compilerOptions.maxProblemsPerUnit);
090: CompilationUnitDeclaration unit = SourceTypeConverter
091: .buildCompilationUnit(sourceTypes,//sourceTypes[0] is always toplevel here
092: SourceTypeConverter.FIELD_AND_METHOD // need field and methods
093: | SourceTypeConverter.MEMBER_TYPE, // need member types
094: // no need for field initialization
095: lookupEnvironment.problemReporter, result);
096:
097: if (unit != null) {
098: lookupEnvironment
099: .buildTypeBindings(unit, accessRestriction);
100: lookupEnvironment.completeTypeBindings(unit, true);
101: }
102: }
103:
104: public abstract AssistParser getParser();
105:
106: public void initializeImportCaches() {
107: ImportBinding[] importBindings = this .unitScope.imports;
108: int length = importBindings == null ? 0 : importBindings.length;
109:
110: this .currentPackageName = CharOperation.concatWith(
111: unitScope.fPackage.compoundName, '.');
112:
113: for (int i = 0; i < length; i++) {
114: ImportBinding importBinding = importBindings[i];
115: if (importBinding.onDemand) {
116: if (this .onDemandImportsCache == null) {
117: this .onDemandImportsCache = new ImportBinding[length
118: - i];
119: }
120: this .onDemandImportsCache[this .onDemandImportCacheCount++] = importBinding;
121: } else {
122: if (!(importBinding.resolvedImport instanceof MethodBinding)
123: || importBinding instanceof ImportConflictBinding) {
124: if (this .importsCache == null) {
125: this .importsCache = new char[length - i][][];
126: }
127: this .importsCache[this .importCacheCount++] = new char[][] {
128: importBinding.compoundName[importBinding.compoundName.length - 1],
129: CharOperation.concatWith(
130: importBinding.compoundName, '.') };
131: }
132: }
133: }
134:
135: this .importCachesInitialized = true;
136: }
137:
138: protected boolean mustQualifyType(char[] packageName,
139: char[] typeName, char[] enclosingTypeNames, int modifiers) {
140:
141: // If there are no types defined into the current CU yet.
142: if (unitScope == null)
143: return true;
144:
145: if (!this .importCachesInitialized) {
146: this .initializeImportCaches();
147: }
148:
149: for (int i = 0; i < this .importCacheCount; i++) {
150: char[][] importName = this .importsCache[i];
151: if (CharOperation.equals(typeName, importName[0])) {
152: char[] fullyQualifiedTypeName = enclosingTypeNames == null
153: || enclosingTypeNames.length == 0 ? CharOperation
154: .concat(packageName, typeName, '.')
155: : CharOperation.concat(CharOperation.concat(
156: packageName, enclosingTypeNames, '.'),
157: typeName, '.');
158: return !CharOperation.equals(fullyQualifiedTypeName,
159: importName[1]);
160: }
161: }
162:
163: if ((enclosingTypeNames == null || enclosingTypeNames.length == 0)
164: && CharOperation.equals(this .currentPackageName,
165: packageName))
166: return false;
167:
168: char[] fullyQualifiedEnclosingTypeName = null;
169:
170: for (int i = 0; i < this .onDemandImportCacheCount; i++) {
171: ImportBinding importBinding = this .onDemandImportsCache[i];
172: Binding resolvedImport = importBinding.resolvedImport;
173:
174: char[][] importName = importBinding.compoundName;
175: char[] importFlatName = CharOperation.concatWith(
176: importName, '.');
177:
178: boolean isFound = false;
179: // resolvedImport is a ReferenceBindng or a PackageBinding
180: if (resolvedImport instanceof ReferenceBinding) {
181: if (enclosingTypeNames != null
182: && enclosingTypeNames.length != 0) {
183: if (fullyQualifiedEnclosingTypeName == null) {
184: fullyQualifiedEnclosingTypeName = CharOperation
185: .concat(packageName,
186: enclosingTypeNames, '.');
187: }
188: if (CharOperation.equals(
189: fullyQualifiedEnclosingTypeName,
190: importFlatName)) {
191: if (importBinding.isStatic()) {
192: isFound = (modifiers & ClassFileConstants.AccStatic) != 0;
193: } else {
194: isFound = true;
195: }
196: }
197: }
198: } else {
199: if (enclosingTypeNames == null
200: || enclosingTypeNames.length == 0) {
201: if (CharOperation.equals(packageName,
202: importFlatName)) {
203: if (importBinding.isStatic()) {
204: isFound = (modifiers & ClassFileConstants.AccStatic) != 0;
205: } else {
206: isFound = true;
207: }
208: }
209: }
210: }
211:
212: // find potential conflict with another import
213: if (isFound) {
214: for (int j = 0; j < this .onDemandImportCacheCount; j++) {
215: if (i != j) {
216: ImportBinding conflictingImportBinding = this .onDemandImportsCache[j];
217: if (conflictingImportBinding.resolvedImport instanceof ReferenceBinding) {
218: ReferenceBinding refBinding = (ReferenceBinding) conflictingImportBinding.resolvedImport;
219: if (refBinding.getMemberType(typeName) != null) {
220: return true;
221: }
222: } else {
223: char[] conflictingImportName = CharOperation
224: .concatWith(
225: conflictingImportBinding.compoundName,
226: '.');
227:
228: if (this .nameEnvironment.nameLookup
229: .findType(
230: String.valueOf(typeName),
231: String
232: .valueOf(conflictingImportName),
233: false,
234: NameLookup.ACCEPT_ALL,
235: false/*don't check restrictions*/) != null) {
236: return true;
237: }
238: }
239: }
240: }
241: return false;
242: }
243: }
244: return true;
245: }
246:
247: /*
248: * Find the node (a field, a method or an initializer) at the given position
249: * and parse its block statements if it is a method or an initializer.
250: * Returns the node or null if not found
251: */
252: protected ASTNode parseBlockStatements(
253: CompilationUnitDeclaration unit, int position) {
254: int length = unit.types.length;
255: for (int i = 0; i < length; i++) {
256: TypeDeclaration type = unit.types[i];
257: if (type.declarationSourceStart < position
258: && type.declarationSourceEnd >= position) {
259: getParser().scanner.setSource(unit.compilationResult);
260: return parseBlockStatements(type, unit, position);
261: }
262: }
263: return null;
264: }
265:
266: private ASTNode parseBlockStatements(TypeDeclaration type,
267: CompilationUnitDeclaration unit, int position) {
268: //members
269: TypeDeclaration[] memberTypes = type.memberTypes;
270: if (memberTypes != null) {
271: int length = memberTypes.length;
272: for (int i = 0; i < length; i++) {
273: TypeDeclaration memberType = memberTypes[i];
274: if (memberType.bodyStart > position)
275: continue;
276: if (memberType.declarationSourceEnd >= position) {
277: return parseBlockStatements(memberType, unit,
278: position);
279: }
280: }
281: }
282: //methods
283: AbstractMethodDeclaration[] methods = type.methods;
284: if (methods != null) {
285: int length = methods.length;
286: for (int i = 0; i < length; i++) {
287: AbstractMethodDeclaration method = methods[i];
288: if (method.bodyStart > position)
289: continue;
290:
291: if (method.isDefaultConstructor())
292: continue;
293:
294: if (method.declarationSourceEnd >= position) {
295:
296: getParser().parseBlockStatements(method, unit);
297: return method;
298: }
299: }
300: }
301: //initializers
302: FieldDeclaration[] fields = type.fields;
303: if (fields != null) {
304: int length = fields.length;
305: for (int i = 0; i < length; i++) {
306: FieldDeclaration field = fields[i];
307: if (field.sourceStart > position)
308: continue;
309: if (field.declarationSourceEnd >= position) {
310: if (field instanceof Initializer) {
311: getParser().parseBlockStatements(
312: (Initializer) field, type, unit);
313: }
314: return field;
315: }
316: }
317: }
318: return null;
319: }
320:
321: protected void reset() {
322: lookupEnvironment.reset();
323: }
324:
325: public static char[] getTypeSignature(TypeBinding typeBinding) {
326: char[] result = typeBinding.signature();
327: if (result != null) {
328: result = CharOperation.replaceOnCopy(result, '/', '.');
329: }
330: return result;
331: }
332:
333: public static char[] getSignature(Binding binding) {
334: char[] result = null;
335: if ((binding.kind() & Binding.TYPE) != 0) {
336: TypeBinding typeBinding = (TypeBinding) binding;
337: result = typeBinding.genericTypeSignature();
338: } else if ((binding.kind() & Binding.METHOD) != 0) {
339: MethodBinding methodBinding = (MethodBinding) binding;
340: int oldMod = methodBinding.modifiers;
341: //TODO remove the next line when method from binary type will be able to generate generic siganute
342: methodBinding.modifiers |= ExtraCompilerModifiers.AccGenericSignature;
343: result = methodBinding.genericSignature();
344: if (result == null) {
345: result = methodBinding.signature();
346: }
347: methodBinding.modifiers = oldMod;
348: }
349: if (result != null) {
350: result = CharOperation.replaceOnCopy(result, '/', '.');
351: }
352: return result;
353: }
354:
355: public static char[][] getSignatures(Binding[] bindings) {
356: int length = bindings == null ? 0 : bindings.length;
357: char[][] signatures = new char[length][];
358: for (int i = 0; i < length; i++) {
359: signatures[i] = getSignature(bindings[i]);
360: }
361: return signatures;
362: }
363: }
|