/* * Copyright 2011 Google Inc. All Rights Reserved. * * 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 com.google.devtools.j2objc.gen; import com.google.common.collect.Sets; import com.google.devtools.j2objc.J2ObjC; import com.google.devtools.j2objc.types.Import; import com.google.devtools.j2objc.util.NameTable; import com.google.devtools.j2objc.util.UnicodeUtils; import java.util.Set; /** * Generates Objective-C header files from compilation units. * * @author Tom Ball */ public class ObjectiveCHeaderGenerator extends ObjectiveCSourceFileGenerator { // The prefix to use for preprocessor variable names. Derived from the path of // the generated file. For example if "my/pkg/Foo.h" is being generated the // prefix would be "MyPkgFoo". protected final String varPrefix; /** * Generate an Objective-C header file for each type declared in the given {@link GenerationUnit}. */ public static void generate(GenerationUnit unit) { new ObjectiveCHeaderGenerator(unit).generate(); } protected ObjectiveCHeaderGenerator(GenerationUnit unit) { super(unit, false); varPrefix = getVarPrefix(unit.getOutputPath()); } @Override protected String getSuffix() { return ".h"; } public void generate() { println(J2ObjC.getFileHeader(getGenerationUnit().getSourceName())); for (String javadoc : getGenerationUnit().getJavadocBlocks()) { print(javadoc); } generateFileHeader(); for (GeneratedType generatedType : getOrderedTypes()) { printTypeDeclaration(generatedType); } generateFileFooter(); save(getOutputPath()); } protected void printTypeDeclaration(GeneratedType generatedType) { print(generatedType.getPublicDeclarationCode()); } protected void generateFileHeader() { printf("#ifndef %s_H\n", varPrefix); printf("#define %s_H\n", varPrefix); pushIgnoreDeprecatedDeclarationsPragma(); pushIgnoreNullabilityCompletenessPragma(); Set<String> seenTypes = Sets.newHashSet(); Set<String> includeFiles = Sets.newTreeSet(); Set<Import> forwardDeclarations = Sets.newHashSet(); includeFiles.add("J2ObjC_header.h"); for (GeneratedType type : getOrderedTypes()) { String name = type.getTypeName(); if (!type.isPrivate()) { seenTypes.add(name); } for (Import imp : type.getHeaderIncludes()) { if (!isLocalType(imp.getTypeName())) { includeFiles.add(imp.getImportFileName()); } } for (Import imp : type.getHeaderForwardDeclarations()) { // Filter out any declarations that are resolved by an include. if (!seenTypes.contains(imp.getTypeName()) && !includeFiles.contains(imp.getImportFileName())) { forwardDeclarations.add(imp); } } } // Print collected includes. newline(); for (String header : includeFiles) { printf("#include \"%s\"\n", header); } printForwardDeclarations(forwardDeclarations); // Print OCNI blocks for (String code : getGenerationUnit().getNativeHeaderBlocks()) { print(code); } } protected void generateFileFooter() { newline(); popIgnoreNullabilityCompletenessPragma(); popIgnoreDeprecatedDeclarationsPragma(); printf("#endif // %s_H\n", varPrefix); } protected static String getVarPrefix(String header) { if (header.endsWith(".h")) { header = header.substring(0, header.length() - 2); } return UnicodeUtils.asValidObjcIdentifier(NameTable.camelCasePath(header)); } /** * Ignores nullability completeness warnings. If clang finds any nullability * annotations, it checks that all annotatable sites have annotations. Java * checker frameworks don't have that requirement. */ protected void pushIgnoreNullabilityCompletenessPragma() { if (getGenerationUnit().hasNullabilityAnnotations()) { newline(); println("#if __has_feature(nullability)"); println("#pragma clang diagnostic push"); println("#pragma GCC diagnostic ignored \"-Wnullability-completeness\""); println("#endif"); } } protected void popIgnoreNullabilityCompletenessPragma() { if (getGenerationUnit().hasNullabilityAnnotations()) { newline(); println("#if __has_feature(nullability)"); println("#pragma clang diagnostic pop"); println("#endif"); } } }