001/*******************************************************************************
002 * Copyright (c) 2017, 2018 Red Hat Inc
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 *     Jens Reimann - initial API and implementation
010 *******************************************************************************/
011package de.dentrassi.varlink.generator.util;
012
013import static org.eclipse.jdt.core.dom.Modifier.ModifierKeyword.PUBLIC_KEYWORD;
014
015import java.io.File;
016import java.io.Writer;
017import java.nio.charset.Charset;
018import java.nio.file.Files;
019import java.nio.file.Path;
020import java.util.List;
021import java.util.function.BiConsumer;
022
023import org.eclipse.jdt.core.ToolFactory;
024import org.eclipse.jdt.core.dom.AST;
025import org.eclipse.jdt.core.dom.ASTNode;
026import org.eclipse.jdt.core.dom.Assignment;
027import org.eclipse.jdt.core.dom.Block;
028import org.eclipse.jdt.core.dom.BodyDeclaration;
029import org.eclipse.jdt.core.dom.CompilationUnit;
030import org.eclipse.jdt.core.dom.FieldAccess;
031import org.eclipse.jdt.core.dom.FieldDeclaration;
032import org.eclipse.jdt.core.dom.MarkerAnnotation;
033import org.eclipse.jdt.core.dom.MethodDeclaration;
034import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
035import org.eclipse.jdt.core.dom.NormalAnnotation;
036import org.eclipse.jdt.core.dom.PackageDeclaration;
037import org.eclipse.jdt.core.dom.ReturnStatement;
038import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
039import org.eclipse.jdt.core.dom.StringLiteral;
040import org.eclipse.jdt.core.dom.Type;
041import org.eclipse.jdt.core.dom.TypeDeclaration;
042import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
043import org.eclipse.jdt.core.formatter.CodeFormatter;
044import org.eclipse.jface.text.Document;
045import org.eclipse.text.edits.TextEdit;
046
047@SuppressWarnings("unchecked")
048public class JdtHelper {
049
050    public static StringLiteral newStringLiteral(final AST ast, final String value) {
051        final StringLiteral result = ast.newStringLiteral();
052        result.setLiteralValue(value);
053        return result;
054    }
055
056    public static void make(final AST ast, final List<? super Object> decl, final ModifierKeyword... keywords) {
057        for (final ModifierKeyword keyword : keywords) {
058            decl.add(ast.newModifier(keyword));
059        }
060    }
061
062    public static void make(final BodyDeclaration decl, final ModifierKeyword... keywords) {
063        make(decl.getAST(), decl.modifiers(), keywords);
064    }
065
066    public static void make(final SingleVariableDeclaration decl, final ModifierKeyword... keywords) {
067        make(decl.getAST(), decl.modifiers(), keywords);
068    }
069
070    public static void addSimpleAnnotation(final BodyDeclaration decl, final String name) {
071        final AST ast = decl.getAST();
072        final MarkerAnnotation ann = ast.newMarkerAnnotation();
073        ann.setTypeName(ast.newName(name));
074        decl.modifiers().add(ann);
075    }
076
077    public static NormalAnnotation addAnnotation(final BodyDeclaration decl, final String name) {
078        final AST ast = decl.getAST();
079        final NormalAnnotation ann = ast.newNormalAnnotation();
080        ann.setTypeName(ast.newName(name));
081        decl.modifiers().add(ann);
082        return ann;
083    }
084
085    public static void createCompilationUnit(final Path root, final String packageName, final String name,
086            final Charset charset, final BiConsumer<AST, CompilationUnit> consumer) {
087
088        final AST ast = AST.newAST(AST.JLS8);
089
090        final CompilationUnit cu = ast.newCompilationUnit();
091
092        final PackageDeclaration pkg = ast.newPackageDeclaration();
093        pkg.setName(ast.newName(packageName));
094        cu.setPackage(pkg);
095
096        final Path path = root.resolve(packageName.replace(".", File.separator)).resolve(name + ".java");
097
098        consumer.accept(ast, cu);
099
100        try {
101            Files.createDirectories(path.getParent());
102
103            // format code
104
105            final CodeFormatter formatter = ToolFactory.createCodeFormatter(null);
106            final String s = cu.toString();
107            final TextEdit result = formatter.format(CodeFormatter.K_COMPILATION_UNIT, s, 0, s.length(), 0, null);
108
109            final Document doc = new Document(s);
110            result.apply(doc);
111
112            // write out
113
114            try (final Writer writer = Files.newBufferedWriter(path, charset)) {
115                writer.append(doc.get());
116            }
117        } catch (final Exception e) {
118            throw new RuntimeException(e);
119        }
120
121    }
122
123    public static void createField(final TypeDeclaration decl, final String typeName, final String fieldName,
124            final ModifierKeyword... keywords) {
125
126        final AST ast = decl.getAST();
127
128        final VariableDeclarationFragment fragment = ast.newVariableDeclarationFragment();
129        fragment.setName(ast.newSimpleName(fieldName));
130
131        final FieldDeclaration fd = ast.newFieldDeclaration(fragment);
132
133        fd.setType(ast.newSimpleType(ast.newName(typeName)));
134        make(fd, keywords);
135
136        decl.bodyDeclarations().add(fd);
137
138    }
139
140    public static void createParameter(final MethodDeclaration decl, final Type type, final String name,
141            final ModifierKeyword... keywords) {
142
143        final AST ast = decl.getAST();
144
145        final SingleVariableDeclaration svd = ast.newSingleVariableDeclaration();
146
147        svd.setType(type);
148        svd.setName(ast.newSimpleName(name));
149        make(svd, keywords);
150
151        decl.parameters().add(svd);
152    }
153
154    public static void createParameter(final MethodDeclaration decl, final String typeName, final String name,
155            final ModifierKeyword... keywords) {
156        final AST ast = decl.getAST();
157        createParameter(decl, ast.newSimpleType(ast.newName(typeName)), name, keywords);
158    }
159
160    public static void createThisAssignment(final Block body, final String name) {
161        final AST ast = body.getAST();
162        final Assignment as = ast.newAssignment();
163        final FieldAccess fa = ast.newFieldAccess();
164        fa.setExpression(ast.newThisExpression());
165        fa.setName(ast.newSimpleName(name));
166        as.setLeftHandSide(fa);
167        as.setRightHandSide(ast.newSimpleName(name));
168        body.statements().add(ast.newExpressionStatement(as));
169    }
170
171    public static <T extends ASTNode> T copyNode(final AST ast, final T node) {
172        return (T) ASTNode.copySubtree(ast, node);
173    }
174
175    public static MethodDeclaration createGetter(final AST ast, final Type type, final String name) {
176        final MethodDeclaration md = ast.newMethodDeclaration();
177        md.setName(ast.newSimpleName("get" + Names.toUpperFirst(name)));
178        make(md, PUBLIC_KEYWORD);
179
180        md.setReturnType2(type);
181
182        final Block body = ast.newBlock();
183        md.setBody(body);
184
185        final ReturnStatement ret = ast.newReturnStatement();
186        body.statements().add(ret);
187
188        final FieldAccess fa = ast.newFieldAccess();
189        fa.setExpression(ast.newThisExpression());
190        fa.setName(ast.newSimpleName(name));
191        ret.setExpression(fa);
192
193        return md;
194    }
195
196}