org.aspectj.org.eclipse.jdt.internal.eval.CodeSnippetToCuMapper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during
compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based
@AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step.
This library is a superset of AspectJ weaver and hence also of AspectJ runtime.
/*******************************************************************************
* Copyright (c) 2000, 2011 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.eval;
import org.aspectj.org.eclipse.jdt.core.CompletionContext;
import org.aspectj.org.eclipse.jdt.core.CompletionProposal;
import org.aspectj.org.eclipse.jdt.core.CompletionRequestor;
import org.aspectj.org.eclipse.jdt.core.Flags;
import org.aspectj.org.eclipse.jdt.core.Signature;
import org.aspectj.org.eclipse.jdt.core.compiler.*;
import org.aspectj.org.eclipse.jdt.internal.codeassist.ISelectionRequestor;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
/**
* Maps back and forth a code snippet to a compilation unit.
* The structure of the compilation unit is as follows:
*
* [package ;]
* [import ;]*
* public class extends {
* [ val$this;]
* public void run() {
*
* }
* }
*
*/
class CodeSnippetToCuMapper implements EvaluationConstants {
/**
* The generated compilation unit.
*/
public char[] cuSource;
/**
* Where the code snippet starts in the generated compilation unit.
*/
public int lineNumberOffset = 0;
public int startPosOffset = 0;
// Internal fields
char[] codeSnippet;
char[] snippetPackageName;
char[][] snippetImports;
char[] snippetClassName;
char[] snippetVarClassName;
char[] snippetDeclaringTypeName;
// Mapping of external local variables
char[][] localVarNames;
char[][] localVarTypeNames;
long complianceVersion;
/**
* Rebuild source in presence of external local variables
*/
public CodeSnippetToCuMapper(
char[] codeSnippet,
char[] packageName,
char[][] imports,
char[] className,
char[] varClassName,
char[][] localVarNames,
char[][] localVarTypeNames,
int[] localVarModifiers,
char[] declaringTypeName,
String lineSeparator,
long complianceVersion) {
this.codeSnippet = codeSnippet;
this.snippetPackageName = packageName;
this.snippetImports = imports;
this.snippetClassName = className;
this.snippetVarClassName = varClassName;
this.localVarNames = localVarNames;
this.localVarTypeNames = localVarTypeNames;
this.snippetDeclaringTypeName = declaringTypeName;
this.complianceVersion = complianceVersion;
buildCUSource(lineSeparator);
}
private void buildCUSource(String lineSeparator) {
StringBuilder buffer = new StringBuilder();
// package declaration
if (this.snippetPackageName != null && this.snippetPackageName.length != 0) {
buffer.append("package "); //$NON-NLS-1$
buffer.append(this.snippetPackageName);
buffer.append(";").append(lineSeparator); //$NON-NLS-1$
this.lineNumberOffset++;
}
// import declarations
char[][] imports = this.snippetImports;
for (int i = 0; i < imports.length; i++) {
buffer.append("import "); //$NON-NLS-1$
buffer.append(imports[i]);
buffer.append(';').append(lineSeparator);
this.lineNumberOffset++;
}
// class declaration
buffer.append("public class "); //$NON-NLS-1$
buffer.append(this.snippetClassName);
// super class is either a global variable class or the CodeSnippet class
if (this.snippetVarClassName != null) {
buffer.append(" extends "); //$NON-NLS-1$
buffer.append(this.snippetVarClassName);
} else {
buffer.append(" extends "); //$NON-NLS-1$
buffer.append(PACKAGE_NAME);
buffer.append("."); //$NON-NLS-1$
buffer.append(ROOT_CLASS_NAME);
}
buffer.append(" {").append(lineSeparator); //$NON-NLS-1$
this.lineNumberOffset++;
if (this.snippetDeclaringTypeName != null){
buffer.append(" "); //$NON-NLS-1$
buffer.append(this.snippetDeclaringTypeName);
buffer.append(" "); //$NON-NLS-1$
buffer.append(DELEGATE_THIS); // val$this
buffer.append(';').append(lineSeparator);
this.lineNumberOffset++;
}
// add some storage location for local variable persisted state
if (this.localVarNames != null) {
for (int i = 0, max = this.localVarNames.length; i < max; i++) {
buffer.append(" "); //$NON-NLS-1$
buffer.append(this.localVarTypeNames[i]);
buffer.append(" "); //$NON-NLS-1$
buffer.append(LOCAL_VAR_PREFIX); // val$...
buffer.append(this.localVarNames[i]);
buffer.append(';').append(lineSeparator);
this.lineNumberOffset++;
}
}
// run() method declaration
if (this.complianceVersion >= ClassFileConstants.JDK1_5) {
buffer.append("@Override "); //$NON-NLS-1$
}
buffer.append("public void run() throws Throwable {").append(lineSeparator); //$NON-NLS-1$
this.lineNumberOffset++;
this.startPosOffset = buffer.length();
buffer.append(this.codeSnippet);
// a line separator is required after the code snippet source code
// in case the code snippet source code ends with a line comment
// http://dev.eclipse.org/bugs/show_bug.cgi?id=14838
buffer.append(lineSeparator).append('}').append(lineSeparator);
// end of class declaration
buffer.append('}').append(lineSeparator);
// store result
int length = buffer.length();
this.cuSource = new char[length];
buffer.getChars(0, length, this.cuSource, 0);
}
/**
* Returns a completion requestor that wraps the given requestor and shift the results
* according to the start offset and line number offset of the code snippet in the generated compilation unit.
*/
public CompletionRequestor getCompletionRequestor(final CompletionRequestor originalRequestor) {
return new CompletionRequestor() {
@Override
public void accept(CompletionProposal proposal) {
switch(proposal.getKind()) {
case CompletionProposal.TYPE_REF:
int flags = proposal.getFlags();
if((flags & Flags.AccEnum) == 0 &&
(flags & Flags.AccInterface) == 0) {
// Remove completion on generated class name or generated global variable class name
char[] packageName = proposal.getDeclarationSignature();
char[] className = Signature.getSignatureSimpleName(proposal.getSignature());
if (CharOperation.equals(packageName, CodeSnippetToCuMapper.this.snippetPackageName)
&& (CharOperation.equals(className, CodeSnippetToCuMapper.this.snippetClassName)
|| CharOperation.equals(className, CodeSnippetToCuMapper.this.snippetVarClassName))) return;
if (CharOperation.equals(packageName, PACKAGE_NAME)
&& CharOperation.equals(className, ROOT_CLASS_NAME)) return;
}
break;
case CompletionProposal.METHOD_REF:
case CompletionProposal.METHOD_DECLARATION:
case CompletionProposal.METHOD_REF_WITH_CASTED_RECEIVER:
// Remove completion on generated method
char[] declaringTypePackageName = Signature.getSignatureQualifier(proposal.getDeclarationSignature());
char[] declaringTypeName = Signature.getSignatureSimpleName(proposal.getDeclarationSignature());
if (CharOperation.equals(declaringTypePackageName, CodeSnippetToCuMapper.this.snippetPackageName)
&& CharOperation.equals(declaringTypeName, CodeSnippetToCuMapper.this.snippetClassName)) return;
if (CharOperation.equals(declaringTypePackageName, PACKAGE_NAME)
&& CharOperation.equals(declaringTypeName, ROOT_CLASS_NAME)) return;
break;
}
originalRequestor.accept(proposal);
}
@Override
public void completionFailure(IProblem problem) {
problem.setSourceStart(problem.getSourceStart() - CodeSnippetToCuMapper.this.startPosOffset);
problem.setSourceEnd(problem.getSourceEnd() - CodeSnippetToCuMapper.this.startPosOffset);
problem.setSourceLineNumber(problem.getSourceLineNumber() - CodeSnippetToCuMapper.this.lineNumberOffset);
originalRequestor.completionFailure(problem);
}
@Override
public void acceptContext(CompletionContext context) {
originalRequestor.acceptContext(context);
}
@Override
public void beginReporting() {
originalRequestor.beginReporting();
}
@Override
public void endReporting() {
originalRequestor.endReporting();
}
@Override
public boolean isIgnored(int completionProposalKind) {
return originalRequestor.isIgnored(completionProposalKind);
}
@Override
public void setIgnored(int completionProposalKind, boolean ignore) {
originalRequestor.setIgnored(completionProposalKind, ignore);
}
@Override
public boolean isAllowingRequiredProposals(int mainKind, int requiredKind) {
return originalRequestor.isAllowingRequiredProposals(mainKind, requiredKind);
}
@Override
public void setAllowsRequiredProposals(int mainKind, int requiredKind, boolean allow) {
originalRequestor.setAllowsRequiredProposals(mainKind, requiredKind, allow);
}
};
}
public char[] getCUSource(String lineSeparator) {
if (this.cuSource == null) {
buildCUSource(lineSeparator);
}
return this.cuSource;
}
/**
* Returns the type of evaluation that corresponds to the given line number in the generated compilation unit.
*/
public int getEvaluationType(int lineNumber) {
int currentLine = 1;
// check package declaration
if (this.snippetPackageName != null && this.snippetPackageName.length != 0) {
if (lineNumber == 1) {
return EvaluationResult.T_PACKAGE;
}
currentLine++;
}
// check imports
char[][] imports = this.snippetImports;
if ((currentLine <= lineNumber) && (lineNumber < (currentLine + imports.length))) {
return EvaluationResult.T_IMPORT;
}
currentLine += imports.length + 1; // + 1 to skip the class declaration line
// check generated fields
currentLine +=
(this.snippetDeclaringTypeName == null ? 0 : 1)
+ (this.localVarNames == null ? 0 : this.localVarNames.length);
if (currentLine > lineNumber) {
return EvaluationResult.T_INTERNAL;
}
currentLine ++; // + 1 to skip the method declaration line
// check code snippet
if (currentLine >= this.lineNumberOffset) {
return EvaluationResult.T_CODE_SNIPPET;
}
// default
return EvaluationResult.T_INTERNAL;
}
/**
* Returns the import defined at the given line number.
*/
public char[] getImport(int lineNumber) {
int importStartLine = this.lineNumberOffset - 1 - this.snippetImports.length;
return this.snippetImports[lineNumber - importStartLine];
}
/**
* Returns a selection requestor that wraps the given requestor and shift the problems
* according to the start offset and line number offset of the code snippet in the generated compilation unit.
*/
public ISelectionRequestor getSelectionRequestor(final ISelectionRequestor originalRequestor) {
return new ISelectionRequestor() {
@Override
public void acceptType(char[] packageName, char[] typeName, int modifiers, boolean isDeclaration, char[] uniqueKey, int start, int end) {
originalRequestor.acceptType(packageName, typeName, modifiers, isDeclaration, uniqueKey, start, end);
}
@Override
public void acceptError(CategorizedProblem error) {
error.setSourceLineNumber(error.getSourceLineNumber() - CodeSnippetToCuMapper.this.lineNumberOffset);
error.setSourceStart(error.getSourceStart() - CodeSnippetToCuMapper.this.startPosOffset);
error.setSourceEnd(error.getSourceEnd() - CodeSnippetToCuMapper.this.startPosOffset);
originalRequestor.acceptError(error);
}
@Override
public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] name, boolean isDeclaration, char[] uniqueKey, int start, int end) {
originalRequestor.acceptField(declaringTypePackageName, declaringTypeName, name, isDeclaration, uniqueKey, start, end);
}
@Override
public void acceptMethod(char[] declaringTypePackageName, char[] declaringTypeName, String enclosingDeclaringTypeSignature, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, String[] parameterSignatures, char[][] typeParameterNames, char[][][] typeParameterBoundNames, boolean isConstructor, boolean isDeclaration, char[] uniqueKey, int start, int end) {
originalRequestor.acceptMethod(declaringTypePackageName, declaringTypeName, enclosingDeclaringTypeSignature, selector, parameterPackageNames, parameterTypeNames, parameterSignatures, typeParameterNames, typeParameterBoundNames, isConstructor, isDeclaration, uniqueKey, start, end);
}
@Override
public void acceptPackage(char[] packageName) {
originalRequestor.acceptPackage(packageName);
}
@Override
public void acceptTypeParameter(char[] declaringTypePackageName, char[] declaringTypeName, char[] typeParameterName, boolean isDeclaration, int start, int end) {
originalRequestor.acceptTypeParameter(declaringTypePackageName, declaringTypeName, typeParameterName, isDeclaration, start, end);
}
@Override
public void acceptMethodTypeParameter(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, int selectorStart, int selectorEnd, char[] typeParameterName,boolean isDeclaration, int start, int end) {
originalRequestor.acceptMethodTypeParameter(declaringTypePackageName, declaringTypeName, selector, selectorStart, selectorEnd, typeParameterName, isDeclaration, start, end);
}
@Override
public void acceptModule(char[] moduleName, char[] uniqueKey, int start, int end) {
originalRequestor.acceptModule(moduleName, uniqueKey, start, end);
}
};
}
}