/* * Copyright 2009-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.jdt.groovy.integration.internal; import java.util.Collections; import org.codehaus.jdt.groovy.internal.compiler.ast.GroovyCompilationUnitDeclaration; import org.codehaus.jdt.groovy.internal.compiler.ast.GroovyParser; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.groovy.core.util.ContentTypeUtils; import org.eclipse.jdt.groovy.core.util.ReflectionUtils; import org.eclipse.jdt.internal.compiler.CompilationResult; import org.eclipse.jdt.internal.compiler.IProblemFactory; import org.eclipse.jdt.internal.compiler.ISourceElementRequestor; import org.eclipse.jdt.internal.compiler.SourceElementNotifier; import org.eclipse.jdt.internal.compiler.SourceElementParser; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt; import org.eclipse.jdt.internal.core.search.indexing.IndexingParser; /** * @author Andrew Eisenberg * @created Aug 27, 2009 */ public class MultiplexingIndexingParser extends IndexingParser { SourceElementNotifier notifier; boolean groovyReportReferenceInfo; ISourceElementRequestor requestor; public MultiplexingIndexingParser(ISourceElementRequestor requestor, IProblemFactory problemFactory, CompilerOptions options, boolean reportLocalDeclarations, boolean optimizeStringLiterals, boolean useSourceJavadocParser) { super(requestor, problemFactory, options, reportLocalDeclarations, optimizeStringLiterals, useSourceJavadocParser); this.notifier = (SourceElementNotifier) ReflectionUtils.getPrivateField(SourceElementParser.class, "notifier", this); this.groovyReportReferenceInfo = reportLocalDeclarations; this.requestor = requestor; } @Override public void setRequestor(ISourceElementRequestor requestor) { super.setRequestor(requestor); this.requestor = requestor; } @Override public CompilationUnitDeclaration parseCompilationUnit(ICompilationUnit unit, boolean fullParse, IProgressMonitor pm) { if (ContentTypeUtils.isGroovyLikeFileName(unit.getFileName())) { // ASSUMPTIONS: // 1) there is no difference between a diet and full parse in the groovy works, so can ignore the fullParse parameter // 2) parsing is for the entire CU (ie- from character 0, to unit.getContents().length) // 3) nodesToCategories map is not necessary. I think it has something to do with JavaDoc, but not sure CompilationResult compilationResult = new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit); // FIXASC Is it ok to use a new parser here everytime? If we don't we sometimes recurse back into the first one GroovyCompilationUnitDeclaration cud = (GroovyCompilationUnitDeclaration) new GroovyParser(this.options, problemReporter, false, true).dietParse(unit, compilationResult); // CompilationUnitDeclaration cud groovyParser.dietParse(sourceUnit, compilationResult); HashtableOfObjectToInt sourceEnds = createSourceEnds(cud); GroovyIndexingVisitor visitor = new GroovyIndexingVisitor(requestor); visitor.doVisit(cud.getModuleNode(), cud.currentPackage); notifier.notifySourceElementRequestor(cud, 0, unit.getContents().length, groovyReportReferenceInfo, sourceEnds, /* We don't care about the @category tag, so pass empty map */Collections.EMPTY_MAP); return cud; } else { return super.parseCompilationUnit(unit, fullParse, pm); } } // FIXASC this code is copied from MultiplexingSourceElementParser. Should combine // FIXASC This should be calculated in GroovyCompilationUnitDeclaration private HashtableOfObjectToInt createSourceEnds(CompilationUnitDeclaration cDecl) { HashtableOfObjectToInt table = new HashtableOfObjectToInt(); if (cDecl.types != null) { for (TypeDeclaration tDecl : cDecl.types) { createSourceEndsForType(tDecl, table); } } return table; } // FIXASC this code is copied from MultiplexingSourceElementParser. Should combine // FIXASC This should be calculated in GroovyCompilationUnitDeclaration private void createSourceEndsForType(TypeDeclaration tDecl, HashtableOfObjectToInt table) { table.put(tDecl, tDecl.sourceEnd); if (tDecl.fields != null) { for (FieldDeclaration fDecl : tDecl.fields) { table.put(fDecl, fDecl.sourceEnd); } } if (tDecl.methods != null) { for (AbstractMethodDeclaration mDecl : tDecl.methods) { table.put(mDecl, mDecl.sourceEnd); } } if (tDecl.memberTypes != null) { for (TypeDeclaration innerTDecl : tDecl.memberTypes) { createSourceEndsForType(innerTDecl, table); } } } }