/*
* Copyright 2011 SpringSource, a division of VMware, Inc
*
* andrew - Initial API and implementation
*
* 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.groovy.ast;
import java.util.Collections;
import java.util.List;
import org.codehaus.groovy.GroovyBugError;
/**
* GRECLIPSE
* A {@link ClassNode} where the {@link GenericsType} information
* is immutable. Provides extra safety in the IDE.
*
* @author Andrew Eisenberg
* @created Jul 20, 2011
*/
public class ImmutableClassNode extends ClassNode {
private volatile boolean genericsInitialized;
private volatile boolean writeProtected;
public ImmutableClassNode(Class c) {
super(c);
}
// ASTNode overrides:
@Override
public void setColumnNumber(int n) {}
@Override
public void setLastColumnNumber(int n) {}
@Override
public void setLastLineNumber(int n) {}
@Override
public void setLineNumber(int n) {}
@Override
public void setNodeMetaData(Object k, Object v) {}
@Override
public void setSourcePosition(ASTNode n) {}
@Override
public void setStart(int i) {}
@Override
public void setEnd(int i) {}
// AnnotatedNode overrides:
@Override
public void setNameStart(int i) {}
@Override
public void setNameEnd(int i) {}
@Override
public void setDeclaringClass(ClassNode cn) {}
@Override
public void setHasNoRealSourcePosition(boolean b) {}
@Override
public void setSynthetic(boolean b) {}
// ClassNode overrides:
@Override
public List<MethodNode> getDeclaredMethods(String name) {
if (lazyInitDone && !writeProtected) {
synchronized (methods.map) {
if (!writeProtected) {
for (Object key : methods.map.keySet()) {
List<MethodNode> list = methods.get(key);
methods.map.put(key, Collections.unmodifiableList(list));
}
methods.map = Collections.unmodifiableMap(methods.map);
writeProtected = true;
}
}
}
return super.getDeclaredMethods(name);
}
@Override
public void setAnnotated(boolean b) {}
@Override
protected void setCompileUnit(CompileUnit cu) {}
@Override
public void setEnclosingMethod(MethodNode mn) {}
@Override
public void setGenericsPlaceHolder(boolean b) {}
@Override
public void setHasInconsistentHierarchy(boolean b) {}
//public void setInterfaces(ClassNode[] cn) {}
@Override
public void setModifiers(int bf) {}
@Override
public void setModule(ModuleNode mn) {}
@Override
public String setName(String s) {
return getName();
}
//public void setRedirect(ClassNode cn) {}
@Override
public void setSuperClass(ClassNode cn) {}
@Override
public void setScript(boolean b) {}
@Override
public void setScriptBody(boolean b) {}
@Override
public void setStaticClass(boolean b) {}
@Override
public void setSyntheticPublic(boolean b) {}
//public void setUnresolvedSuperClass(ClassNode cn) {}
@Override
public void setUsingGenerics(boolean b) {}
@Override
public void setGenericsTypes(GenericsType[] genericsTypes) {
if (genericsInitialized && genericsTypes != this.genericsTypes) {
throw new GroovyBugError("Attempt to change an immutable Groovy class: " + getName());
}
if (genericsTypes != null) {
GenericsType[] immutable = new GenericsType[genericsTypes.length];
for (int i = 0; i < genericsTypes.length; i++) {
immutable[i] = new ImmutableGenericsType(genericsTypes[i], getName());
}
genericsTypes = immutable;
}
super.setGenericsTypes(genericsTypes);
genericsInitialized = true;
}
static class ImmutableGenericsType extends GenericsType {
ImmutableGenericsType(GenericsType delegate, String typeName) {
this.typeName = typeName;
super.setType(delegate.getType());
super.setName(delegate.getName());
super.setPlaceholder(delegate.isPlaceholder());
super.setResolved(delegate.isResolved());
super.setWildcard(delegate.isWildcard());
super.setLowerBound(delegate.getLowerBound());
super.setUpperBounds(delegate.getUpperBounds());
}
private final String typeName;
@Override
public void setType(ClassNode type) {
throw new GroovyBugError("Attempt to change an immutable Groovy class: " + typeName);
}
@Override
public void setPlaceholder(boolean placeholder) {
throw new GroovyBugError("Attempt to change an immutable Groovy class: " + typeName);
}
@Override
public void setResolved(boolean res) {
throw new GroovyBugError("Attempt to change an immutable Groovy class: " + typeName);
}
@Override
public void setName(String name) {
throw new GroovyBugError("Attempt to change an immutable Groovy class: " + typeName);
}
@Override
public void setWildcard(boolean wildcard) {
throw new GroovyBugError("Attempt to change an immutable Groovy class: " + typeName);
}
@Override
public void setUpperBounds(ClassNode[] bounds) {
throw new GroovyBugError("Attempt to change an immutable Groovy class: " + typeName);
}
@Override
public void setLowerBound(ClassNode bound) {
throw new GroovyBugError("Attempt to change an immutable Groovy class: " + typeName);
}
}
}