1 /* 2 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.javac.parser; 27 28 import java.util.HashSet; 29 import java.util.Set; 30 31 /** 32 * Methods used to support text blocks lint. 33 * 34 * <p><b>This is NOT part of any supported API. 35 * If you write code that depends on this, you do so at your own risk. 36 * This code and its internal interfaces are subject to change or 37 * deletion without notice.</b> 38 */ 39 class TextBlockSupport { 40 enum WhitespaceChecks { 41 INCONSISTENT, 42 TRAILING 43 }; 44 45 /** Check that the use of white space in content is not problematic. 46 */ checkWhitespace(String string)47 static Set<WhitespaceChecks> checkWhitespace(String string) { 48 // Start with empty result set. 49 Set<WhitespaceChecks> checks = new HashSet<>(); 50 // No need to check empty strings. 51 if (string.isEmpty()) { 52 return checks; 53 } 54 // Maximum common indentation. 55 int outdent = 0; 56 // No need to check indentation if opting out (last line is empty.) 57 char lastChar = string.charAt(string.length() - 1); 58 boolean optOut = lastChar == '\n' || lastChar == '\r'; 59 // Split string based at line terminators. 60 String[] lines = string.split("\\R"); 61 int length = lines.length; 62 // Extract last line. 63 String lastLine = length == 0 ? "" : lines[length - 1]; 64 if (!optOut) { 65 // Prime with the last line indentation (may be blank.) 66 outdent = indexOfNonWhitespace(lastLine); 67 for (String line : lines) { 68 // Blanks lines have no influence (last line accounted for.) 69 if (!line.isBlank()) { 70 outdent = Integer.min(outdent, indexOfNonWhitespace(line)); 71 if (outdent == 0) { 72 break; 73 } 74 } 75 } 76 } 77 // Last line is representative. 78 String start = lastLine.substring(0, outdent); 79 for (String line : lines) { 80 // Fail if a line does not have the same indentation. 81 if (!line.isBlank() && !line.startsWith(start)) { 82 // Mix of different white space 83 checks.add(WhitespaceChecks.INCONSISTENT); 84 } 85 // Line has content even after indent is removed. 86 if (outdent < line.length()) { 87 // Is the last character a white space. 88 lastChar = line.charAt(line.length() - 1); 89 if (Character.isWhitespace(lastChar)) { 90 // Has trailing white space. 91 checks.add(WhitespaceChecks.TRAILING); 92 } 93 } 94 } 95 return checks; 96 } 97 indexOfNonWhitespace(String string)98 private static int indexOfNonWhitespace(String string) { 99 return string.length() - string.stripLeading().length(); 100 } 101 } 102